﻿using System;
using System.Collections.Generic;
using System.Text;
using Hime.Redist.Parsers;

namespace xowl.gmi.compiler.transform
{
    class PatternBuiltin : Pattern
    {
        protected static Random rand = new Random();

        /* 
         * create(x y) =
         *      ObjectPropertyAssertion(command:create x y)
         * delete(x y) =
         *      ObjectPropertyAssertion(command:delete x y)
         * attach(s x y) =
         *      ClassAssertion(command:Attach ?<gen>)
         *      ObjectPropertyAssertion(command:symbol ?<gen> s)
         *      ObjectPropertyAssertion(command:parent ?<gen> x)
         *      ObjectPropertyAssertion(command:child ?<gen> y)
         * detach(s x y) =
         *      ClassAssertion(command:Detach ?<gen>)
         *      ObjectPropertyAssertion(command:symbol ?<gen> s)
         *      ObjectPropertyAssertion(command:parent ?<gen> x)
         *      ObjectPropertyAssertion(command:child ?<gen> y)
         * order(s x y i)
         *      ClassAssertion(command:Order ?<gen>)
         *      ObjectPropertyAssertion(command:symbol ?<gen> s)
         *      ObjectPropertyAssertion(command:parent ?<gen> x)
         *      ObjectPropertyAssertion(command:child ?<gen> y)
         *      DataPropertyAssertion(command:order ?<gen> i)
         * unorder(s x y i)
         *      ClassAssertion(command:Unorder ?<gen>)
         *      ObjectPropertyAssertion(command:symbol ?<gen> s)
         *      ObjectPropertyAssertion(command:parent ?<gen> x)
         *      ObjectPropertyAssertion(command:child ?<gen> y)
         *      DataPropertyAssertion(command:order ?<gen> i)
         * set(x y) =
         *      DataPropertyAssertion(command:set x y)
         * unset(x y) =
         *      DataPropertyAssertion(command:unset x y)
         * connect(c n c x y) =
         *      ClassAssertion(command:Connect ?<gen>)
         *      ObjectPropertyAssertion(command:connector ?<gen> c)
         *      ObjectPropertyAssertion(command:node ?<gen> n)
         *      ObjectPropertyAssertion(command:from ?<gen> x)
         *      ObjectPropertyAssertion(command:to ?<gen> y)
         * disconnect(c n x y) =
         *      ClassAssertion(command:Disconnect ?<gen>)
         *      ObjectPropertyAssertion(command:connector ?<gen> c)
         *      ObjectPropertyAssertion(command:node ?<gen> n)
         *      ObjectPropertyAssertion(command:from ?<gen> x)
         *      ObjectPropertyAssertion(command:to ?<gen> y)
         * 
         * indexer(p x y i) =
         *      ClassAssertion(lib:Indexer ?<gen>)
         *      ObjectPropertyAssertion(lib:property ?<gen> p)
         *      ObjectPropertyAssertion(lib:origin ?<gen> x)
         *      ObjectPropertyAssertion(lib:target ?<gen> y)
         *      DataPropertyAssertion(lib:index ?<gen> i)
         * 
         * from(x y) =
         *      ObjectPropertyAssertion(meta:from x y)
         * trace(x y) =
         *      ObjectPropertyAssertion(meta:trace x y)
         * route(r x y) =
         *      ObjectPropertyAssertion(r x y)
         * token(x y) =
         *      ObjectPropertyAssertion(meta:token x y)
        */

        private string name;
        private List<PatternPart> parameters;
        private bool isMeta;
        private bool isNegative;

        public PatternBuiltin(string name, PatternPart p1)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
        }
        public PatternBuiltin(string name, PatternPart p1, bool isMeta, bool isNegative)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.isMeta = isMeta;
            this.isNegative = isNegative;
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, bool isMeta, bool isNegative)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.isMeta = isMeta;
            this.isNegative = isNegative;
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3, bool isMeta, bool isNegative)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
            this.isMeta = isMeta;
            this.isNegative = isNegative;
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3, PatternPart p4)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
            this.parameters.Add(p4);
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3, PatternPart p4, bool isMeta, bool isNegative)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
            this.parameters.Add(p4);
            this.isMeta = isMeta;
            this.isNegative = isNegative;
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3, PatternPart p4, PatternPart p5)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
            this.parameters.Add(p4);
            this.parameters.Add(p5);
        }
        public PatternBuiltin(string name, PatternPart p1, PatternPart p2, PatternPart p3, PatternPart p4, PatternPart p5, bool isMeta, bool isNegative)
        {
            this.name = name;
            this.parameters = new List<PatternPart>();
            this.parameters.Add(p1);
            this.parameters.Add(p2);
            this.parameters.Add(p3);
            this.parameters.Add(p4);
            this.parameters.Add(p5);
            this.isMeta = isMeta;
            this.isNegative = isNegative;
        }
        public PatternBuiltin(Context context, SyntaxTreeNode ast, bool isMeta, bool isNegative)
        {
            this.name = (ast.Children[0].Symbol as SymbolTokenText).ValueText;
            this.parameters = new List<PatternPart>();
            this.isMeta = isMeta;
            this.isNegative = isNegative;
            foreach (SyntaxTreeNode param in ast.Children[1].Children)
                this.parameters.Add(TransformationRule.GetPatternPart(context, param));
        }

        public void Write(System.IO.StreamWriter writer)
        {
            if (isMeta) writer.Write("^");
            else writer.Write(" ");
            writer.Write(" ");
            if (isNegative) writer.Write("-");
            else writer.Write(" ");
            writer.Write(" ");

            writer.Write(name);
            writer.Write("(");
            bool first = true;
            foreach (PatternPart part in parameters)
            {
                if (!first) writer.Write(" ");
                first = false;
                part.Write(writer);
            }
            writer.Write(")");
        }

        public void WriteOWL(System.IO.StreamWriter writer)
        {
            if (isMeta) writer.Write("Meta(");
            if (isNegative) writer.Write("Not(");
            switch (name)
            {
                case "create": WriteOWLCreate(writer); break;
                case "delete": WriteOWLDelete(writer); break;
                case "attach": WriteOWLAttach(writer); break;
                case "detach": WriteOWLDetach(writer); break;
                case "order": WriteOWLOrder(writer); break;
                case "unorder": WriteOWLUnorder(writer); break;
                case "set": WriteOWLSet(writer); break;
                case "unset": WriteOWLUnset(writer); break;
                case "connect": WriteOWLConnect(writer); break;
                case "disconnect": WriteOWLDisconnect(writer); break;
                case "indexer": WriteOWLIndexer(writer); break;
                case "from": WriteOWLFrom(writer); break;
                case "trace": WriteOWLTrace(writer); break;
                case "lfrom": WriteOWLLFrom(writer); break;
                case "ltrace": WriteOWLLTrace(writer); break;
                case "route": WriteOWLRoute(writer); break;
                case "token": WriteOWLToken(writer); break;
                default: throw new Exception("Builtin not found: " + name);
            }
            if (isNegative) writer.Write(")");
            if (isMeta) writer.Write(")");
        }
        private void WriteOWLCreate(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(command:create ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLDelete(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(command:delete ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLAttach(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Attach ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:symbol ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:parent ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:child ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLDetach(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Detach ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:symbol ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:parent ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:child ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLOrder(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Order ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:symbol ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:parent ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:child ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tDataPropertyAssertion(command:index ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLUnorder(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Unorder ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:symbol ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:parent ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:child ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tDataPropertyAssertion(command:index ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLSet(System.IO.StreamWriter writer)
        {
            writer.Write("DataPropertyAssertion(command:set ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLUnset(System.IO.StreamWriter writer)
        {
            writer.Write("DataPropertyAssertion(command:unset ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLConnect(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Connect ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:connector ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:node ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:from ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:to ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLDisconnect(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(command:Disconnect ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:connector ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:node ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:from ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(command:to ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLIndexer(System.IO.StreamWriter writer)
        {
            writer.Write("ClassAssertion(lib:Indexer ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(lib:property ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(lib:origin ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(lib:target ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tDataPropertyAssertion(lib:index ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[4].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLFrom(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(meta:from ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLTrace(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(meta:trace ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLLFrom(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(meta:lfrom ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:connector ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:property ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:origin ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:target ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLLTrace(System.IO.StreamWriter writer)
        {
            string gen = rand.Next().ToString("X");

            writer.Write("ClassAssertion(meta:ltrace ?");
            writer.Write(gen);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:connector ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[0].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:property ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:origin ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.WriteLine(")");

            writer.Write("\t\t\tObjectPropertyAssertion(meta:target ?");
            writer.Write(gen);
            writer.Write(" ");
            parameters[3].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLRoute(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(" ");
            parameters[2].WriteOWL(writer);
            writer.Write(")");
        }
        private void WriteOWLToken(System.IO.StreamWriter writer)
        {
            writer.Write("ObjectPropertyAssertion(meta:token ");
            parameters[0].WriteOWL(writer);
            writer.Write(" ");
            parameters[1].WriteOWL(writer);
            writer.Write(")");
        }
    }
}
